<?php
namespace app\common;

use think\cache\driver\Redis;

class RedisLock {

    private $_redis;


    public function __construct() {

        $this->_redis = $this->connect();
    }

    /**
     * 获取锁
     * @param  String  $lockName    锁标识
     * @param  Int     $timeout 锁过期时间
     * @return Boolean
     */
    public function lock($lockName, $timeout=2){
        $identifier=uniqid();  #获取唯一标识符，作为锁的值
        $timeout=ceil($timeout); #确保是整数
        while(true)   #循环获取锁
        {
            if($this->_redis->setnx($lockName, $identifier)) #查看$lockName是否被上锁
            {
                $this->_redis->expire($lockName, $timeout);  #为$lockName设置过期时间，防止死锁
                return $identifier;        #返回一维标识符
            }
            elseif ($this->_redis->ttl($lockName)===-1)
            {
                $this->_redis->expire($lockName, $timeout);  #检测是否有设置过期时间，没有则加上（假设，客户端A上一步没能设置时间就进程奔溃了，客户端B就可检测出来，并设置时间）
            }
            usleep(0.01);   #停止0.001ms
        }
        return false;
    }

    /**
     * 释放锁
     * @param  String  $lockName 锁标识
     * @param  String  $identifier 锁值
     * @return Boolean
     */
    public function unlock($lockName,$identifier){
        if($this->_redis->get($lockName)==$identifier) #判断是锁有没有被其他客户端修改
        {
            $this->_redis->multi();#开启事务
            $this->_redis->del($lockName); #释放锁
            $this->_redis->exec();#提交事务
            return true;
        }
        else
        {
            return false; #其他客户端修改了锁，不能删除别人的锁
        }
    }


    /**
     * 创建redis连接
     * @return Link
     */
    private function connect(){
        try{
            $redis = new Redis();

            //有密码时设置
//            $redis->auth('');

        }catch(Exception $e){
            throw new Exception($e->getMessage());
            return false;
        }
        return $redis;
    }

}